#!/bin/bash
# sb2-config-gcc-toolchain - configure a cross-gcc compiler for SB2
#
# Copyright (c) 2008 Nokia Corporation.
# Copyright (C) 2007 Lauri Leukkunen <lle@rahina.org>
# Licensed under GPL version 2

my_path=$_
if [ $(basename $my_path) != $(basename $0) ]; then
	my_path=$0
	if [ $(basename $my_path) = $my_path ]; then
		my_path=$(which $my_path)
	fi
fi

function log_config_action()
{
	tstamp=`/bin/date '+%Y-%m-%d %H:%M:%S'`
	echo "$tstamp	$*" >>$SBOX_CONFIG_DIR/CONFIG-LOG
}

# Get the original arguments that were specified to sb2-init from
function usage()
{
	cat <<EOF
sb2-config-gcc-toolchain - Configure a cross-gcc compiler for SB2
Usage:
	sb2-config-gcc-toolchain [OPTION]... [COMPILER]

COMPILER is of the form $HOME/arm-2006q3/bin/arm-linux-gcc

Options:
	################
    -t target         set target name
    -C "options"      add extra options for the compiler, for example:
                      "-fgnu89-inline"
    -L "options"      add extra options for the linker, for example:
                      "--sysroot=/"
    -A arch           manually override target architecture
    -h                print this help
    -m mapping_mode   target uses mapping_mode as default mode
    -S SBOX_DIR       define value for SBOX_DIR
    -R TARGET_ROOT    define value for SBOX_TARGET_ROOT
    -V                this toolchain is a secondary toolchain,
                      tools require version numbers in pathnames
    -v                verbose operation

EOF
	exit 2
}

function write_gcc_config()
{
	gcc_version=$1

	if [ -n "$gcc_version" ] ; then
		gcc_version_id=`echo $gcc_version | sed -e 's/[^0-9a-zA-Z]/_/g'`
	fi

	SBOX_TARGET_TOOLCHAIN_DIR=$(dirname "$SBOX_CROSS_GCC_DIR")
	SBOX_CROSS_GCC_PREFIX_LIST=$GCC_TARGET-:$SB2INIT_CROSS_GCC_PREFIX_LIST:$GCC_PREFIX

	# Note: "sb2" script will replace "@SBOX_TARGET_ROOT@" by the real 
	# value when the session is created.
	SBOX_EXTRA_CROSS_LD_ARGS="$SBOX_EXTRA_CROSS_LD_ARGS -rpath-link @SBOX_TARGET_ROOT@/usr/lib:@SBOX_TARGET_ROOT@/lib"
	SBOX_CROSS_GCC_SUBST_PREFIX=$GCC_PREFIX

	cat - > $HOME/.scratchbox2/$TARGET/sb2.config.d/gcc$gcc_version_id.config.sh <<EOF
# gcc configuration file generated by sb2-config-gcc-toolchain.
SB2_GCC_INIT_ORIG_ARGS="$SB2_GCC_INIT_ORIG_ARGS"
SB2_GCC_INIT_TIME=$SB2_GCC_INIT_TIME
SB2_GCC_INIT_ID="$SB2_GCC_INIT_ID"
SB2_GCC_INIT_ARCH="$ARCH"

SBOX_GCC_TARGET=$GCC_TARGET
SBOX_DEFAULT_GCC_PREFIX=$GCC_PREFIX
SBOX_CROSS_GCC_NAME=cross-gcc
SBOX_CROSS_GCC_VERSION="$SBOX_CROSS_GCC_VERSION"
SBOX_CROSS_GCC_SHORTVERSION="$SBOX_CROSS_GCC_SHORTVERSION"
SBOX_CROSS_GCC_PREFIX_LIST=$SBOX_CROSS_GCC_PREFIX_LIST
SBOX_CROSS_GCC_SUBST_PREFIX=$SBOX_CROSS_GCC_SUBST_PREFIX
SBOX_CROSS_GCC_SPECS_FILE="$SBOX_CROSS_GCC_SPECS_FILE"
SBOX_CROSS_GCC_DIR=$SBOX_CROSS_GCC_DIR
SBOX_CROSS_GCC_LD_ARGS=

SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS"
SBOX_EXTRA_CROSS_COMPILER_STDINC="$SBOX_EXTRA_CROSS_COMPILER_STDINC"
SBOX_EXTRA_CROSS_LD_ARGS="$SBOX_EXTRA_CROSS_LD_ARGS"
EOF

	cat - > $HOME/.scratchbox2/$TARGET/sb2.config.d/gcc.config$gcc_version_id.lua <<EOF
-- Automatically created gcc config for SB2's lua scripts. Do not edit.

gcc_config$gcc_version_id = {
	target_toolchain_dir="$SBOX_TARGET_TOOLCHAIN_DIR",

	cross_gcc_prefix_list="$SBOX_CROSS_GCC_PREFIX_LIST",
	cross_gcc_dir="$SBOX_CROSS_GCC_DIR",
	cross_gcc_progs_path="$SBOX_CROSS_GCC_PROGS_PATH",
	cross_gcc_version="$SBOX_CROSS_GCC_VERSION",
	cross_gcc_shortversion="$SBOX_CROSS_GCC_SHORTVERSION",

	extra_cross_compiler_args="$SBOX_EXTRA_CROSS_COMPILER_ARGS",

	cross_gcc_subst_prefix="$SBOX_CROSS_GCC_SUBST_PREFIX",
	cross_gcc_specs_file="$SBOX_CROSS_GCC_SPECS_FILE",
	extra_cross_compiler_stdinc="$SBOX_EXTRA_CROSS_COMPILER_STDINC",
	block_cross_compiler_args="$SBOX_BLOCK_CROSS_COMPILER_ARGS",

	extra_cross_ld_args="$SBOX_EXTRA_CROSS_LD_ARGS",
	block_cross_ld_args="$SBOX_BLOCK_CROSS_LD_ARGS",
}

add_cross_compiler(gcc_config$gcc_version_id, "$gcc_version")

EOF

	if [ -n "$verbose" ] ; then
		echo "Finished writing sb2.gcc.config"
	fi
}

# SB2_GCC_INIT_* variables are used to record who & when this
# toolchain was initialized
# It is possible to set SB2_GCC_INIT_ID externally (for example, if
# another program is used to initialize the system)
SB2_GCC_INIT_ORIG_ARGS="$*"
SB2_GCC_INIT_TIME=`date +%Y-%m-%d_%H:%M:%S`
if [ -z "$SB2_GCC_INIT_ID" ]; then
	SB2_GCC_INIT_ID="user '$USER'"
fi

SBOX_EXTRA_CROSS_COMPILER_ARGS=""

if [ -z "$*" ]; then
	usage
fi

verbose=""

while getopts t:m:C:L:A:M:hS:R:Vv option
do
	case $option in
	(A) ARCH=$OPTARG ;;
	(M) MACHINE_ARCH=$OPTARG ;;
	(h) usage ;;
	(t) TARGET=$OPTARG ;;
	(m) MAPPING_MODE=$OPTARG ;;
	(C) SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS $OPTARG " ;;
	(L) SBOX_EXTRA_CROSS_LD_ARGS="$SBOX_EXTRA_CROSS_LD_ARGS $OPTARG " ;;
	(S) SBOX_DIR=$OPTARG ;;
	(R) SBOX_TARGET_ROOT=$OPTARG ;;
	(V) SECONDARY_COMPILER=yes ;;
	(v) verbose=yes ;;
	(*) usage ;;
	esac
done
shift $(($OPTIND - 1))

case "$1" in
*:*)	# Has a path to specs
	GCC=`echo $1 | cut -d : -f 1`
	GCC_SPECS=`echo $1 | cut -d : -f 2`
	;;
*)	GCC=$1
	GCC_SPECS=""
	;;
esac

# ---------- Check parameters

if [ -z "$SBOX_DIR" ]; then
	SBOX_DIR=$(readlink -f $(dirname $(readlink -f $my_path))/..)
fi

if [ -z "$TARGET" ]; then
        echo "Error: no target given"
        exit 1
fi

SBOX_CONFIG_DIR=~/.scratchbox2/$TARGET/sb2.config.d 

if [ -z "$SBOX_TARGET_ROOT" ]; then
        echo "Error: no target_root given"
        exit 1
fi

if [ ! -d $SBOX_TARGET_ROOT ]; then
        echo "Error: Target root directory does not exist"
        exit 1
fi

if [ -z "$MAPPING_MODE" ]; then
        echo "Error: no mapping mode given"
        exit 1
fi

if [ ! -d $SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE ]; then
	echo "Invalid mapping mode: $MAPPING_MODE"
	exit 1
fi

if [ -z "$GCC" ]; then
	echo "Error: no compiler given"
	exit 1
fi

case "$GCC_SPECS" in
"")	# not specified, this is ok
	;;
/*)	# absolute path
	if [ ! -f $GCC_SPECS ]; then
		echo "Error: compiler specs file ($GCC_SPECS) does not exist."
		exit 1
	fi
	;;
*)	# relative path
	echo "Error: path to specs file ($GCC_SPECS) is not absolute."
	exit 1
esac

GCC_FULLPATH=$(which $GCC)
# test that gcc exists and can be executed
if [ $? != 0 ]; then
	echo "$GCC doesn't exist"
	exit 1
fi

SBOX_CROSS_GCC_DIR=$(dirname $(which $GCC))
if [ $GCC -v > /dev/null 2>&1 != 0 ]; then
	echo "Invalid compiler specified: $GCC"
	exit 1
fi

# ---------- end of parameter checks

case "$(basename $GCC)" in
(*-*)	# $GCC contains a prefix
	GCC_PREFIX=$(basename $GCC | sed 's/-gcc$/-/')
	;;
(*)	# No embedded prefix
	GCC_PREFIX=""
	;;
esac

SBOX_CROSS_GCC_VERSION=`$GCC -dumpversion`

# Create a version string with two digits
SBOX_CROSS_GCC_SHORTVERSION=`echo $SBOX_CROSS_GCC_VERSION |
	sed -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\)\..*/\1/'`

GCC_TARGET=$($GCC -dumpmachine)

if [ -z "$ARCH" ]; then
	if [ -n "$verbose" ] ; then
		echo "Using $GCC to detect target architecture:"
	fi
	ARCH=$(echo $GCC_TARGET | awk -F- '{ print $1 }')
else
	if [ -n "$verbose" ] ; then
		echo "Target architecture set to $ARCH"
	fi
fi
if [ -z "$MACHINE_ARCH" ]; then
	MACHINE_ARCH=$ARCH
fi

# Path where gcc searches for sub-tools (ld, as, cc1,..)
SBOX_CROSS_GCC_PROGS_PATH=$($GCC -print-search-dirs|grep ^programs:|sed 's/programs: =//')

# default for the cross-gcc prefix list:
# these may be changed by modes/$MAPPING_MODE/sb2rc

SB2INIT_CROSS_GCC_PREFIX_LIST=$ARCH-linux-

# $ARCH and $MACHINE_ARCH have been set, get mode-specific settings..
if [ -f $SBOX_SESSION_DIR/modes/$MAPPING_MODE/sb2rc ]; then
	if [ -n "$verbose" ] ; then
		echo "Reading mode-specific settings.."
	fi
	. $SBOX_SESSION_DIR/modes/$MAPPING_MODE/sb2rc "initializing"
fi


# Use "specs" file for gcc if it exists, otherwise add -I/usr/include to params
SBOX_CROSS_GCC_SPECS_FILE=""
SBOX_EXTRA_CROSS_COMPILER_STDINC=""

# FIXME: SBOX_CROSS_GCC_SPECS_FILE may point to $SBOX_DIR/share/scratchbox2/modes
# after this. It should point to a session-specific location, but we don't have any
# mechanism for that currently.
if [ -n "$GCC_SPECS" ]; then
	# the file was specified on the command line
	SBOX_CROSS_GCC_SPECS_FILE="$GCC_SPECS"
# else try to locate a specs file which was provided with gcc
elif [ -f $SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-$SBOX_CROSS_GCC_VERSION-specs-$ARCH ]; then
	SBOX_CROSS_GCC_SPECS_FILE="$SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-$SBOX_CROSS_GCC_VERSION-specs-$ARCH"
elif [ -f $SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-$SBOX_CROSS_GCC_VERSION-specs ]; then
	SBOX_CROSS_GCC_SPECS_FILE="$SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-$SBOX_CROSS_GCC_VERSION-specs"
elif [ -f $SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-$SBOX_CROSS_GCC_SHORTVERSION-specs ]; then
	SBOX_CROSS_GCC_SPECS_FILE="$SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-$SBOX_CROSS_GCC_SHORTVERSION-specs"
elif [ -f $SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-specs ]; then
	SBOX_CROSS_GCC_SPECS_FILE="$SBOX_DIR/share/scratchbox2/modes/$MAPPING_MODE/gcc-specs"
else
	SBOX_EXTRA_CROSS_COMPILER_STDINC="-I/usr/include"
fi

# Note: "sb2" script will replace "@SBOX_TARGET_ROOT@" by the real 
# value when the session is created.
SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS -L@SBOX_TARGET_ROOT@/usr/lib -L@SBOX_TARGET_ROOT@/lib"

# test if the cross compiler needs to be silenced about /usr/include
# usage ("gcc -E -Wno-poison-system-directories" is not a reliable way for
# testing this; instead check if ld has the related flag)
# Ensure its bin directory is in PATH to prevent "unable to find 'ld'" error.
txt=`PATH="$(dirname $GCC_FULLPATH):$PATH" $GCC_FULLPATH -Wl,--help | grep no-poison-system-directories`
case "$txt" in
	(*no-poison-system-directories*)	# option is available
		SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS -Wno-poison-system-directories"
		;;
	(*)					# not available.
		;;
esac

##### HOST_GCC_INC=$(echo "#include <stdio.h>" | gcc -M -E - | SBOX_DIR=$SBOX_DIR perl -e 'while(<STDIN>) { $foo{$1} = 1 if m/\/usr([^[:space:]]*\/include)/;}; foreach my $k (keys %foo) {print " -isystem $ENV{SBOX_DIR}/share/scratchbox2/host_usr$k"};')

if [ -z "$SECONDARY_COMPILER" ] ; then
	write_gcc_config
else
	write_gcc_config $SBOX_CROSS_GCC_VERSION
fi

if [ -n "$verbose" ] ; then
	echo "gcc configured."
fi

log_config_action "gcc configured ($SBOX_CROSS_GCC_VERSION)"
if [ -n "$SBOX_CROSS_GCC_SPECS_FILE" ]; then
	log_config_action "(gcc specs from $SBOX_CROSS_GCC_SPECS_FILE)"
fi

exit 0
